package com.yx.changdao.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yx.changdao.common.entity.SysMenu;
import com.yx.changdao.common.entity.SysUser;
import com.yx.changdao.common.exception.AlertException;
import com.yx.changdao.common.mapper.SysMenuMapper;
import com.yx.changdao.common.vo.MenuTreeVo;
import com.yx.changdao.common.utils.Faster;
import com.yx.changdao.common.utils.JsonUtils;
import com.yx.changdao.common.utils.SysUtils;
import com.yx.changdao.common.vo.menu.*;
import com.yx.changdao.service.SysMenuService;
import com.yx.changdao.service.SysUserRoleService;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: <br />
 * SysMenuServiceImpl 系统菜单服务实现
 * <p>
 * <br />
 * @Auther: Zhangjiashun
 * @create 2019/11/18 9:36
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    protected Map<String, SysMenu> menusMapping;
    protected List<SysMenu> treeMenus;


    /**
     * 获取菜单树
     *
     * @return 菜单树
     */
    private List<SysMenu> setMenuTree(String parentId) {
        // 遍历父级菜单下所有子菜单。
        List<SysMenu> menus = this.list(new QueryWrapper<SysMenu>().lambda()
                .eq(SysMenu::getMenuParent, parentId)
                .orderByAsc(SysMenu::getMenuSort));

        for (SysMenu menu : menus) {
            this.menusMapping.put(menu.getMenuId(), menu);
            List<SysMenu> subs = this.setMenuTree(menu.getMenuId());
            if (0 == subs.size()) {
                continue;
            }
            menu.setSubMenu(subs);
        }
        return menus;
    }

    /**
     * 添加菜单
     *
     * @return 添加后的菜单
     */
    @Override
    public SysMenu addMenu(SysMenu menu) {
        if (StringUtils.isEmpty(menu.getMenuParent())) {
            menu.setMenuParent("0");
        }
        menu.setMenuUri(StringUtils.isBlank(menu.getMenuUri()) ? "#" : menu.getMenuUri());
        return this.save(menu) ? menu : null;
    }

    /**
     * 添加菜单
     *
     * @param icon         菜单图标
     * @param menuName     菜单名
     * @param menuParent   父级菜单
     * @param uri          对应前端页面名
     * @param sort         菜单排序
     * @param permissionId 权限id
     * @return 添加后的菜单
     */
    @Override
    public SysMenu addMenu(String icon, String menuName, String menuParent, String uri, int sort, String permissionId) {
        SysMenu menu = new SysMenu();
        menu.setMenuIcon(icon);
        menu.setMenuName(menuName);
        menu.setMenuParent(menuParent);
        menu.setMenuUri(uri);
        menu.setMenuSort(sort);
        menu.setPermissionId(permissionId);
        return this.addMenu(menu);
    }

    /**
     * 获取展示菜单
     *
     * @return 菜单列表
     */
    @Override
    public List<SysMenu> getDisplayMenus() {
        this.menusMapping = new HashMap<>();
        this.treeMenus = this.setMenuTree("0");
        return this.getDisplayMenus(this.getTreeMenus());
    }

    /**
     * 获取展示菜单
     *
     * @return 菜单列表
     */
    @Override
    public List<MenuTreeVo> getAllDisplayMenus() {
        return setAllMenuTree("0");
    }

    /**
     * 获取菜单树
     *
     * @return 菜单树
     */
    private List<MenuTreeVo> setAllMenuTree(String parentId) {
        // 遍历父级菜单下所有子菜单。
        List<SysMenu> menus = this.list(new QueryWrapper<SysMenu>().lambda()
                .eq(SysMenu::getMenuParent, parentId)
                .orderByAsc(SysMenu::getMenuSort));
        ArrayList<MenuTreeVo> treeVos = new ArrayList<>();
        if(!menus.isEmpty()){
            menus.forEach(t -> {
                MenuTreeVo menuTreeVo = new MenuTreeVo();
                BeanUtils.copyProperties(t, menuTreeVo);
                treeVos.add(menuTreeVo);
            });
        }
        for (MenuTreeVo menu : treeVos) {
            List<MenuTreeVo> subs = this.setAllMenuTree(menu.getMenuId());
            if (0 == subs.size()) {
                continue;
            }
            menu.setSubMenu(subs);
        }
        return treeVos;
    }
    /**
     * 更新菜单
     *
     * @param menu 菜单
     * @return 是否更新成功
     * @throws AlertException 异常
     */
    @Override
    public Boolean updateMenu(SysMenu menu) throws AlertException {
        String menuParent = menu.getMenuParent();
        if (StringUtils.isNotBlank(menuParent)) {
            SysMenu parentMenu = this.getById(menuParent);
            if (parentMenu == null) {
                throw new AlertException("不存在的父级菜单id" + menu.getMenuParent());
            }
        }
        return this.updateById(menu);
    }

    /**
     * 删除菜单
     *
     * @param menuId 菜单id
     * @return 是否删除成功
     * @throws AlertException 异常
     */
    @Override
    public Boolean delMenu(String menuId) throws AlertException {
        // 先判断是否存在子菜单。
        if (0 < this.count(new QueryWrapper<SysMenu>().lambda().eq(SysMenu::getMenuParent, menuId))) {
            throw new AlertException("菜单存在子菜单，删除失败。");
        }
        return this.removeById(menuId);
    }


    public List<SysMenu> getDisplayMenus(List<SysMenu> menus) {
        List<SysMenu> ms = new ArrayList<>();
        for (SysMenu m : menus) {
            if (!this.isPermitted(m.getPermissionId())) {
                continue;
            }
            SysMenu menu = m.clone();
            menu.setSubMenu(this.getDisplayMenus(menu.getSubMenu()));
            ms.add(menu);
        }
        return ms;
    }


    private boolean isPermitted(String permission_id) {
        if (!SecurityUtils.getSubject().isAuthenticated()) {
            return false;
        }
        return !StringUtils.isNotBlank(permission_id)
                || SecurityUtils.getSubject().isPermitted(permission_id);
    }

    private List<SysMenu> getTreeMenus() {
        return new ArrayList<>(this.treeMenus);
    }

    @Autowired
    protected SysUserRoleService sysUserRoleService;


    @Override
    public List<MenuVO> menus() {

        SysUser sysUser = SysUtils.currentUser();

        List<String> permissionIds =
                sysUserRoleService.getUserPermissionIds(sysUser.getUserId());

        List<MenuVO> list = new ArrayList<>();

        List<SysMenu> menuPars = list(new QueryWrapper<SysMenu>()
                .eq(SysMenu.MENU_PARENT, 0)
                .in(SysMenu.PERMISSION_ID,permissionIds)
                .orderByAsc(SysMenu.MENU_SORT));


        Set<String> paths = menuPars.stream().map(t -> t.getMenuUri()).collect(Collectors.toSet());

        for (SysMenu t : menuPars) {

            MenuVO menu = new MenuVO();

            menu.setName(t.getMenuName());
            menu.setPath(t.getMenuUri());
            menu.setName(t.getMenuFile()); //页面地址

            MetaVO meta = new MetaVO();
            meta.setTitle(t.getMenuName());
            meta.setIcon(t.getMenuIcon());

            menu.setMeta(meta);

            List<SysMenu> children =
                    list(new QueryWrapper<SysMenu>()
                            .eq(SysMenu.MENU_PARENT, t.getMenuId())
                            .in(SysMenu.PERMISSION_ID,permissionIds)
                            .orderByAsc(SysMenu.MENU_SORT));

            if(children.size() == 1){

                menu.setRedirect(children.get(0).getMenuUri().concat("/"));
            }else{
                menu.setRedirect("#");
            }
            children.forEach(c -> {
                ChildrenVO chi = new ChildrenVO();
                chi.setName(c.getMenuName());

                chi.setPath(c.getMenuUri());
                chi.setName(c.getMenuFile()); //页面地址

                MetaVO cmeta = new MetaVO();

                String replace = c.getMenuName().replace("-总控", "")
                        .replace("-执行", "");

                cmeta.setTitle(replace);

                chi.setMeta(cmeta);

                menu.getChildren().add(chi);
            });
            list.add(menu);
        }

        return list;
    }



    @Override
    public List<ZMenuTVO> route() throws AlertException {

        SysUser sysUser = SysUtils.currentUser();

        List<String> userPermissionIds =
                sysUserRoleService.getUserPermissionIds(sysUser.getUserId());

        List<ZMenuTVO> list = new ArrayList<>();

        List<SysMenu> menus = list(new QueryWrapper<SysMenu>().orderByAsc(SysMenu.MENU_SORT));

        menus.forEach(t -> {

            ZMenuTVO zMenuTVO = new ZMenuTVO();
            zMenuTVO.setName(t.getMenuFile());

            MetaVO meta = new MetaVO();
            meta.setTitle(t.getMenuName());
            meta.setIcon(t.getMenuIcon());

            zMenuTVO.setMeta(meta);

            if(userPermissionIds.contains(t.getPermissionId())){
                zMenuTVO.setHidden(false);
            }else{
                zMenuTVO.setHidden(true);
            }

            list.add(zMenuTVO);
        });

        return list;
    }
}
